package com.chaosj.xml;

import cn.hutool.core.io.resource.ClassPathResource;
import cn.hutool.json.JSONUtil;
import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.nio.charset.Charset;
import java.util.List;

/**
 * @className: Dom4jParser
 * @description:
 * @author: caoyangjie
 * @date: 2022/5/1
 **/
@Slf4j
public class Dom4jParser {

    public static void main(String[] args) {
        doGenerate("service_2001100000101.xml","com.dcits.webservice.client","/home/caoyangjie/IdeaProjects/spring-stack-skills/skill-xml/src/main/java");
//        S2001100000101Request request = new S2001100000101Request();
//        S2001100000101Request.SysHead sysHead = new S2001100000101Request.SysHead();
//        sysHead.setAplGnd("");
//        sysHead.setServiceScene("");
//        sysHead.setServiceCode("");
//        request.setSysHead(sysHead);
//        S2001100000101Request.AppHead appHead = new S2001100000101Request.AppHead();
//        appHead.setAplFamAdr("");
//        request.setAppHead(appHead);
//        S2001100000101Request.Body body = new S2001100000101Request.Body();
//        body.setTranDate("");
//        body.setAplGnd("");
//        request.setBody(body);
//        System.err.println(JsonUtil.toJsonEmpty(request));
//        System.err.println(JSONUtil.toJsonStr(request));
    }

    public static void doGenerate(String serviceDefineXmlPath, String packageName, String generateDir){
        SAXReader reader = new SAXReader();
        try {
            Document document = reader.read(new ClassPathResource(serviceDefineXmlPath).getReader(Charset.forName("UTF-8")));
            String serviceCode = document.getRootElement().getName();
            GeneratePojo classCode = new GeneratePojo();
            // 获取 serviceCode
            classCode.setServiceCode(serviceCode);
            // 遍历两次， 第一次 解析 Request , 第二次解析 Response
            for(int k=0; k <=1; k++){
                int finalK = k;
                sysHead(k==0, document).elements().forEach(e->{
                    Element elm = (Element) e;
                    doParser(elm, classCode, null, finalK==0, "sys");
                });
                appHead(k==0, document).elements().forEach(e->{
                    Element elm = (Element) e;
                    doParser(elm, classCode, null, finalK==0, "app");
                });
                body(k==0, document).elements().forEach(e->{
                    Element elm = (Element) e;
                    doParser(elm, classCode, null, finalK==0, "body");
                });
            }
            classCode.generateJava(packageName, generateDir);
        } catch (DocumentException e) {
            log.error(e.getMessage());
        }
    }

    private static void doParser(Element elm, GeneratePojo classCode, GeneratePojo.ClassItem clsItem, boolean isRequest, String type){
        int attrCount = elm.attributeCount();
        if( attrCount > 0 ){
            String fieldName = elm.getName();
            String aliasName = attrValue(elm, "metadataid");
            String chineseName = attrValue(elm, "chinese_name");
            String typeValue = attrValue(elm, "type");
            boolean isStruct = Boolean.valueOf(attrValue(elm, "is_struct"));
            GeneratePojo.FieldItem item = new GeneratePojo.FieldItem(fieldName, aliasName, chineseName, typeValue, isStruct);
            if( elm.elements().size() > 0 ){
                GeneratePojo.ClassItem cItem = new GeneratePojo.ClassItem();
                elm.elements().forEach(e->{
                    Element cfElm = (Element) e;
                    cItem.setType(elm.attributeValue("type"));
                    cItem.setClassName(elm.getName());
                    doParser(cfElm, classCode, cItem, isRequest, type);
                });
                if( clsItem == null ){
                    loadItems(isRequest, type, classCode, false).add(cItem);
                }else{
                    clsItem.getClassItems().add(cItem);
                }
                return;
            }
            if( clsItem == null ){
                loadItems(isRequest, type, classCode, true).add(item);
            }else{
                clsItem.getItems().add(item);
            }
        }else{
//            String className = elm.getName();
            GeneratePojo.ClassItem classItem = new GeneratePojo.ClassItem();
            if( "sdo".equalsIgnoreCase(elm.getName()) || "array".equalsIgnoreCase(elm.getName()) ){
                elm.elements().forEach(e->{
                    doParser((Element) e, classCode, clsItem, isRequest, type);
                });
                return;
            }else{
                GeneratePojo.ClassItem finalClassItem = classItem;
                elm.elements().forEach(e->{
                    foreachElements(elm, classCode, isRequest, type, finalClassItem, (Element) e);
                });
            }
            if( clsItem == null ){
                loadItems(isRequest, type, classCode, false).add(classItem);
            }else{
                clsItem.getClassItems().add(classItem);
            }
        }
    }

    private static void foreachElements(Element elm, GeneratePojo classCode, boolean isRequest, String type, GeneratePojo.ClassItem classItem, Element e) {
        Element clsElm = e;
        classItem.setType(elm.getName());
        classItem.setClassName(clsElm.getName());
        doParser(clsElm, classCode, classItem, isRequest, type);
    }

    public static List loadItems(boolean isRequest, String type, GeneratePojo classCode, boolean isFieldItem) {
         GeneratePojo.IFunc func = isRequest ? classCode.getRequest() : classCode.getResponse();
         List items;
         switch (type){
             case "sys":
                 items = isFieldItem ? ((GeneratePojo.IItem)func.getSysHead()).getItems() : ((GeneratePojo.IItem)func.getSysHead()).getClassItems();
             break;
             case "app":
                 items = isFieldItem ? ((GeneratePojo.IItem)func.getAppHead()).getItems() : ((GeneratePojo.IItem)func.getAppHead()).getClassItems();
             break;
             case "body":
                 items = isFieldItem ? ((GeneratePojo.IItem)func.getBody()).getItems(): ((GeneratePojo.IItem)func.getBody()).getClassItems();
             break;
             default:
                 throw new IllegalStateException("Unexpected value: " + type);
         }
         return items;
    }

    public static Element sysHead(boolean request, Document document){
        return (Element) document.selectSingleNode((request?"//request":"//response")+"//sdoroot//SYS_HEAD");
    }

    public static Element appHead(boolean request, Document document){
        return (Element) document.selectSingleNode((request?"//request":"//response")+"//sdoroot//APP_HEAD");
    }

    public static Element body(boolean request, Document document){
        return (Element) document.selectSingleNode((request?"//request":"//response")+"//sdoroot//BODY");
    }

    public static String attrValue(Element element, String attr){
        return element.attributeValue(attr);
    }
}
